#ifndef TILE_HPP_INCLUDED
#define TILE_HPP_INCLUDED

#include <string>
#include <vector>

#include "citizen.hpp"
#include "city_fwd.hpp"
#include "formula_callable.hpp"
#include "resource.hpp"
#include "river.hpp"
#include "terrain_fwd.hpp"
#include "terrain_improvement_fwd.hpp"
#include "tile_fwd.hpp"
#include "tile_logic.hpp"
#include "wml_node.hpp"

class barter_market;
class world;

namespace hex {

class heightmap;

class tile : public game_logic::formula_callable {
public:
	struct parse_error {};
	tile(const location& loc, const std::string& str);
	~tile();
	const location& loc() const { return loc_; }
	const_terrain_ptr terrain() const { return terrain_; }

	void set_heightmap(heightmap& heights) const;

	void draw(const heightmap& heights) const;
	void draw(const heightmap& heights, const graphics::texture& t, GLfloat height_adj) const;
	void draw_water() const;
	void draw_infrastructure() const;
	void draw_borders(const world& w) const;
	void draw_description() const;

	void add_resource(const std::string& name, int quality);

	void process_occupations(world& w);
	void end_turn(const world& w);

	struct resource_instance {
		int quality;
		const_resource_ptr resource;
	};

	const std::vector<resource_instance>& resources() const { return resources_; }

	bool empty() const { return citizens_.empty(); }

	void migrate_to(tile& o);

	void place_orders(barter_market& mkt);

	std::vector<citizen_ptr>& citizens() { return citizens_; }
	const std::vector<citizen_ptr>& citizens() const { return citizens_; }

	int move_cost() const;

	void set_city(city_ptr c);
	city_ptr city();
	const_city_ptr city() const;

	void build_road(DIRECTION dir);
	int road(DIRECTION dir) const { return roads_[dir]; }

	void add_river(DIRECTION dir, river_ptr river);

	void clear_influences();
	void add_influence(city_ptr c);
	const std::vector<city_ptr>& influences() const { return influences_; }

	const std::vector<std::string>& causes_of_deaths() const { return causes_of_deaths_; }
	const_government_ptr owner() const;

	const_terrain_improvement_ptr can_build_improvement() const;
	void build_improvement(const_terrain_improvement_ptr improvement);
	const_terrain_improvement_ptr improvement() const { return improvement_; }

	int seed() const { return seed_; }
private:
	void process_deaths_and_births(const world& w);
	void process_cultural_conversions();
	variant get_value(const std::string& key) const;

	std::vector<std::string> causes_of_deaths_;

	location loc_;
	const_terrain_ptr terrain_;
	const_terrain_improvement_ptr improvement_;
	city_ptr city_;
	std::vector<city_ptr> influences_;

	std::vector<resource_instance> resources_;
	std::vector<citizen_ptr> citizens_;

	int roads_[6];
	river_ptr rivers_[6];

	struct point {
		point() : init(false)
		{}
		GLfloat position[3];
		GLfloat normal[3];
		bool init;
	};

	point center_;
	point corners_[6];
	int seed_;

	void draw_point(const point& p) const;
	void calculate_corner(int n);
};
}

#endif
